namespace MoreLinq;

using System;
using System.Collections.Generic;

static partial class MoreEnumerable
{
    /// <summary>
    /// Traces the elements of a source sequence for diagnostics.
    /// </summary>
    /// <typeparam name="TSource">Type of element in the source sequence</typeparam>
    /// <param name="source">Source sequence whose elements to trace.</param>
    /// <returns>
    /// Return the source sequence unmodified.
    /// </returns>
    /// <remarks>
    /// This a pass-through operator that uses deferred execution and
    /// streams the results.
    /// </remarks>

    public static IEnumerable<TSource> Trace<TSource>(this IEnumerable<TSource> source)
    {
            return Trace(source, (string?)null);
        }

    /// <summary>
    /// Traces the elements of a source sequence for diagnostics using
    /// custom formatting.
    /// </summary>
    /// <typeparam name="TSource">Type of element in the source sequence</typeparam>
    /// <param name="source">Source sequence whose elements to trace.</param>
    /// <param name="format">
    /// String to use to format the trace message. If null then the
    /// element value becomes the traced message.
    /// </param>
    /// <returns>
    /// Return the source sequence unmodified.
    /// </returns>
    /// <remarks>
    /// This a pass-through operator that uses deferred execution and
    /// streams the results.
    /// </remarks>

    public static IEnumerable<TSource> Trace<TSource>(this IEnumerable<TSource> source, string? format)
    {
            if (source == null) throw new ArgumentNullException(nameof(source));

            return TraceImpl(source, string.IsNullOrEmpty(format)
                ? x => x?.ToString() ?? string.Empty
                : x => string.Format(null, format, x));
        }

    /// <summary>
    /// Traces the elements of a source sequence for diagnostics using
    /// a custom formatter.
    /// </summary>
    /// <typeparam name="TSource">Type of element in the source sequence</typeparam>
    /// <param name="source">Source sequence whose elements to trace.</param>
    /// <param name="formatter">Function used to format each source element into a string.</param>
    /// <returns>
    /// Return the source sequence unmodified.
    /// </returns>
    /// <remarks>
    /// This a pass-through operator that uses deferred execution and
    /// streams the results.
    /// </remarks>

    public static IEnumerable<TSource> Trace<TSource>(this IEnumerable<TSource> source, Func<TSource, string> formatter)
    {
            if (source == null) throw new ArgumentNullException(nameof(source));
            if (formatter == null) throw new ArgumentNullException(nameof(formatter));
            return TraceImpl(source, formatter);
        }

    static IEnumerable<TSource> TraceImpl<TSource>(IEnumerable<TSource> source, Func<TSource, string> formatter)
    {
            return source.Pipe(x => System.Diagnostics.Trace.WriteLine(formatter(x)));
        }
}
